#!/usr/bin/python
import twitter
import oauth
import cgi
import logging
import config
import re
import urllib

from string import Template
from db import TwitterUser, GoogleUser, Db, IdList, MODE_LIST, MODE_MENTION, MODE_DM, MODE_HOME, MODE_NONE
from pytz.gae import pytz
from mylocale import gettext, LOCALES
from utils import Utils
from django.utils import simplejson
from google.appengine.api import urlfetch
from google.appengine.ext import webapp
from google.appengine.api import xmpp, memcache
from google.appengine.api.xmpp import PRESENCE_SHOW_AWAY, PRESENCE_SHOW_CHAT
from google.appengine.api.capabilities import CapabilitySet
from google.appengine.ext.webapp.util import run_wsgi_app
from google.appengine.runtime.apiproxy_errors import CapabilityDisabledError, DeadlineExceededError

SHORT_COMMANDS = {
  '@': 'reply',
  'r': 'reply',
  'd': 'dm',
  'h': 'home',
  'ho': 'home',
  'lt': 'list',
  'tl': 'timeline',
  's': 'switch',
  'se': 'search',
  'fo': 'follow',
  'uf': 'unfollow',
  'b': 'block',
  'ub': 'unblock',
  'm': 'msg',
  'f': 'fav',
  'uv': 'unfav',
  'u': 'user',
  '?': 'help',
  'he': 'help'
}

_locale = config.DEFAULT_LANGUAGE
_ = lambda x: gettext(x, locale=_locale)
_screen_name_regex = r'[a-zA-Z0-9_]+'
_check_screen_name = lambda screen_name: bool(re.match('^%s$' % _screen_name_regex, screen_name))
_if_dm = lambda x: True if len(str(x)) < 17 else False

class Dummy(object):
  def __getattr__(self, _):
    raise NotImplementedError

  def __getitem__(self, _):
    raise NotImplementedError


def send_presence(*args, **kwargs):
  try:
    v = xmpp.send_presence(*args, **kwargs)
  except xmpp.Error:
    v = xmpp.OTHER_ERROR
  return v


def send_message(*args, **kwargs):
  while CapabilitySet('xmpp').is_enabled():
    try:
      v = xmpp.send_message(*args, **kwargs)
    except xmpp.Error:
      pass
    else:
      return v
  return xmpp.OTHER_ERROR


def get_presence(*args, **kwargs):
  try:
    v = xmpp.get_presence(*args, **kwargs)
  except xmpp.Error:
    v = False
  return v


class XMPP_handler(webapp.RequestHandler):
  def post(self):
    try:
      message = xmpp.Message(self.request.POST)
    except xmpp.InvalidMessageError:
      return
    else:
      try:
        result = self.process(message)
      except CapabilityDisabledError:
        send_presence(self.request.get('from'), presence_type=PRESENCE_SHOW_AWAY)
      except DeadlineExceededError:
        pass
      else:
        if result:
          send_message(message.sender, result)
        IdList.flush(self._google_user.jid)
        Db.set_datastore(self._google_user)
        send_presence(self.request.get('from'), presence_type=PRESENCE_SHOW_CHAT)

  def process(self, message):
    global _locale
    jid = message.sender.split('/')[0]
    self._google_user = GoogleUser.get_by_jid(jid)
    if self._google_user is None:
      self._google_user = GoogleUser.add(jid)
    _locale = self._google_user.locale
    self._twitter_user = Dummy()
    self._api = Dummy()
    if self._google_user.enabled_user:
      self._twitter_user = TwitterUser.get_by_twitter_name(self._google_user.enabled_user, self._google_user.jid)
      if self._twitter_user is None:
        self._google_user.enabled_user = ''
      else:
        self._api = twitter.Api(consumer_key=config.OAUTH_CONSUMER_KEY,
                                consumer_secret=config.OAUTH_CONSUMER_SECRET,
                                access_token_key=self._twitter_user.access_token_key,
                                access_token_secret=self._twitter_user.access_token_secret)
    self._utils = Utils(self._google_user.jid)
    try:
      result = self.parse_command(message.body)
    except NotImplementedError:
      result = _('INVALID_COMMAND')
    except twitter.TwitterInternalServerError:
      result = _('INTERNAL_SERVER_ERROR')
    except twitter.TwitterAuthenticationError:
      self._google_user.retry += 1
      if self._google_user.retry >= config.MAX_RETRY:
        GoogleUser.disable(self._google_user.jid)
      else:
        Db.set_datastore(self._google_user)
      result = _('NO_AUTHENTICATION')
    return result

  def parse_command(self, content):
    content = content.rstrip()
    if not content:
      return ''
    if content.startswith(self._google_user.command_prefix):
      args = content[len(self._google_user.command_prefix):].split(' ')
      args[0] = args[0].lower()
      if args[0] in SHORT_COMMANDS:
        args[0] = SHORT_COMMANDS[args[0]]
      func_name = 'func_' + args[0]
      if func_name in dir(self):
        func = getattr(self, func_name)
      else:
        return _('INVALID_COMMAND')
      return func(args[1:])
    else:
      if len(content) > twitter.CHARACTER_LIMIT:
        return _('WORDS_COUNT_EXCEED') % (len(content), twitter.CHARACTER_LIMIT)
      if type(content) == unicode:
        content = content.encode('UTF8')
      try:
        self._api.post_update(content)
      except twitter.TwitterError, e:
        if 'Status is a duplicate' in e.message:
          return _('STATUS_DUPLICATE')
        else:
          return e.message
      return _('SUCCESSFULLY_UPDATE_STATUS')

  def func_msg(self, args):
    length = len(args)
    if length == 1:
      short_id = args[0]
      try:
        id = self._utils.restore_short_id(short_id)
      except ValueError:
        pass
      else:
        statuses = list()
        for __ in range(config.MAX_REPLY_STATUS):
          try:
            status = self._api.get_status(id)
          except twitter.TwitterError, e:
            if 'No status found' in e.message:
              if statuses:
                break
              else:
                return _('STATUS_NOT_FOUND') % short_id
            else:
              return ''
          if not status:
            break
          statuses.append(status)
          while 'retweeted_status' in status:
            statuses.append(status['retweeted_status'])
            status = status['retweeted_status']
          if 'in_reply_to_status_id' in status:
            id = status['in_reply_to_status_id']
          else:
            break
        return _('STATUSES_CONVERSATION') + '\n\n' + self._utils.parse_statuses(statuses, reverse=False)
    raise NotImplementedError


  def func_reply(self, args):
    length = len(args)
    if not length or (length == 1 and (args[0][0].lower() == 'p' and args[0][1:].isdigit())):
      page = args[0][1:] if length else 1
      statuses = self._api.get_mentions(page=int(page))
      return _('MENTIONS') + _('PAGE') % str(page) + '\n\n' + self._utils.parse_statuses(statuses)
    elif length > 1:
      short_id = args[0][0:3]
      try:
        id = self._utils.restore_short_id(short_id)
      except ValueError:
        pass
      else:
        try:
          status = self._api.get_status(id)
        except twitter.TwitterError, e:
          if 'No status found' in e.message:
            return _('STATUS_NOT_FOUND') % short_id
          else:
            return ''
        if status is None:
          return ''
        if len(args[0]) == 3:
          user = status['user']['screen_name']
          message = u'@%s %s' % (user, ' '.join(args[1:]))
        elif args[0][3:].isdigit():
          names = re.findall('@(%s)' % _screen_name_regex, status['text'])
          if int(args[0][3:])<=len(names):
            user = names[int(args[0][3:])-1]
            message = u'@%s %s' % (user , ' '.join(args[1:]))
        if len(message) > twitter.CHARACTER_LIMIT:
          return _('WORDS_COUNT_EXCEED') % (len(message), twitter.CHARACTER_LIMIT)
        if type(message) == unicode:
          message = message.encode('UTF8')
        try:
          self._api.post_update(message, id)
        except twitter.TwitterError, e:
          if 'Status is a duplicate' in e.message:
            return _('STATUS_DUPLICATE')
          else:
            return ''
        return _('SUCCESSFULLY_REPLY_TO') % user
    raise NotImplementedError

  def func_time(self, args):
    length = len(args)
    if not length:
      return _('INTERVAL') % str(self._google_user.interval)
    elif length == 1 and args[0].isdigit():
      self._google_user.interval = int(args[0])
      return _('INTERVAL') % str(self._google_user.interval)
    raise NotImplementedError

  def func_dm(self, args):
    length = len(args)
    if not length or (length == 1 and args[0][0].lower() == 'p' and args[0][1:].isdigit()):
      if (length):
        page = args[0][1:]
      else:
	page = "1"
      page = int(page)
      statuses = self._api.get_direct_messages(page)
      return _('DIRECT_MESSAGES') + _('PAGE') % str(page) + '\n\n' + self._utils.parse_statuses(statuses)
    elif length > 1 and ' '.join(args[1:]):
      message = ' '.join(args[1:])
      screen_name = args[0]
      if not _check_screen_name(screen_name):
        try:
          id = self._utils.restore_short_id(screen_name)
        except ValueError:
          return _('INVALID_USERNAME')
        else:
          if _if_dm(id):
            status = memcache.get(str(id), namespace='dm')
            if status is None:
              statuses = self._api.get_direct_messages(since_id=id-1, max_id=id+1, count=1)
              if statuses:
                status = statuses[0]
              else:
                return _('DM_NOT_FOUND') % screen_name
            screen_name = status['sender']['screen_name']
          else:
            status = self._api.get_status(id)
            if status:
              screen_name = status['user']['screen_name']
            else:
              return _('STATUS_NOT_FOUND') % screen_name
      if len(message) > twitter.CHARACTER_LIMIT:
        return _('WORDS_COUNT_EXCEED') % (len(message), twitter.CHARACTER_LIMIT)
      if type(message) == unicode:
        message = message.encode('UTF8')
      try:
        self._api.post_direct_message(screen_name, message)
      except twitter.TwitterError, e:
        if 'Not found' in e.message:
          return _('USER_NOT_FOUND') % screen_name
        elif 'You cannot send messages to users who are not following you' in e.message:
          return _('MESSAGE_TO_NOT_FOLLOWED')
        else:
          return ''
      return _('SUCCESSFULLY_MESSAGE') % screen_name
    raise NotImplementedError

  def func_follow(self, args):
    if len(args) == 1:
      screen_name = args[0]
      if not _check_screen_name(screen_name):
        try:
          id = self._utils.restore_short_id(screen_name[0:3])
        except ValueError:
          return _('INVALID_USERNAME')
        else:
          status = self._api.get_status(id)
          if status and len(screen_name) == 3:
            screen_name = status['user']['screen_name']
          elif screen_name[3:].isdigit():
            names = re.findall('@(%s)' % _screen_name_regex, status['text'])
            if int(screen_name[3:])<=len(names):
              screen_name = names[int(screen_name[3:])-1]
          else:
            return _('STATUS_NOT_FOUND') % screen_name
      try:
        self._api.create_friendship(screen_name)
      except twitter.TwitterError, e:
        if 'You\'ve already requested to follow' in e.message:
          return _('ALREADY_FOLLOWED') % screen_name
        elif 'blocked' in e.message:
          return _('BLOCKED') % screen_name
        elif 'Not found' in e.message:
          return _('USER_NOT_FOUND') % screen_name
        else:
          logging.warn('create_friendship:\n', e.message)
          return ''
      return _('SUCCESSFULLY_FOLLOW') % screen_name
    raise NotImplementedError

  def func_unfollow(self, args):
    if len(args) == 1:
      screen_name = args[0]
      if not _check_screen_name(screen_name):
        try:
          id = self._utils.restore_short_id(screen_name[0:3])
        except ValueError:
          return _('INVALID_USERNAME')
        else:
          status = self._api.get_status(id)
          if status and len(screen_name) == 3:
            screen_name = status['user']['screen_name']
          elif screen_name[3:].isdigit():
            names = re.findall('@(%s)' % _screen_name_regex, status['text'])
            if int(screen_name[3:])<=len(names):
              screen_name = names[int(screen_name[3:])-1]
          else:
            return _('STATUS_NOT_FOUND') % screen_name
      try:
        self._api.destroy_friendship(screen_name)
      except twitter.TwitterError, e:
        if 'Not found' in e.message:
          return _('USER_NOT_FOUND') % screen_name
        else:
          logging.warn('destroy_friendship:\n', e.message)
          return ''
      return _('SUCCESSFULLY_UNFOLLOW') % screen_name
    raise NotImplementedError

  def func_if(self, args):
    length = len(args)
    if 1 <= length <= 2:
      user_a = args[0]
      user_b = self._google_user.enabled_user if length == 1 else args[1]
      if not _check_screen_name(user_a):
        if length == 1:
          try:
            id = self._utils.restore_short_id(user_a[0:3])
          except ValueError:
            return _('INVALID_USERNAME')
          else:
            status = self._api.get_status(id)
            if status and len(user_a) == 3:
              user_a = status['user']['screen_name']
            elif user_a[3:].isdigit():
              names = re.findall('@(%s)' % _screen_name_regex, status['text'])
              if int(user_a[3:])<=len(names):
                user_a = names[int(user_a[3:])-1]
            else:
              return _('STATUS_NOT_FOUND') % user_a
        elif not _check_screen_name(user_b):
          return _('INVALID_USERNAME')
      try:
        result = self._api.exists_friendship(user_a, user_b)
      except twitter.TwitterError, e:
        if 'Could not find both specified users' in e.message:
          return _('USER_NOT_FOUND') % args[0]
        else:
          logging.warn('exists_friendship:\n', e.message)
          return ''
      if result:
        return _('FOLLOWING') % (user_a, user_b)
      else:
        return _('NOT_FOLLOWING') % (user_a, user_b)
    raise NotImplementedError

  def func_block(self, args):
    if len(args) == 1:
      screen_name = args[0]
      if not _check_screen_name(screen_name):
        try:
          id = self._utils.restore_short_id(screen_name[0:3])
        except ValueError:
          return _('INVALID_USERNAME')
        else:
          status = self._api.get_status(id)
          if status and len(screen_name) == 3:
            screen_name = status['user']['screen_name']
          elif screen_name[3:].isdigit():
            names = re.findall('@(%s)' % _screen_name_regex, status['text'])
            if int(screen_name[3:])<=len(names):
              screen_name = names[int(screen_name[3:])-1]
          else:
            return _('STATUS_NOT_FOUND') % screen_name
      try:
        self._api.create_block(screen_name)
      except twitter.TwitterError, e:
        if 'Not found' in e.message:
          return _('USER_NOT_FOUND') % screen_name
        else:
          logging.warn('create_block:\n', e.message)
          return ''
      return _('SUCCESSFULLY_BLOCK') % screen_name
    raise NotImplementedError

  def func_spam(self, args):
    if len(args) == 1:
      screen_name = args[0]
      if not _check_screen_name(screen_name):
        try:
          id = self._utils.restore_short_id(screen_name[0:3])
        except ValueError:
          return _('INVALID_USERNAME')
        else:
          status = self._api.get_status(id)
          if status and len(screen_name) == 3:
            screen_name = status['user']['screen_name']
          elif screen_name[3:].isdigit():
            names = re.findall('@(%s)' % _screen_name_regex, status['text'])
            if int(screen_name[3:])<=len(names):
              screen_name = names[int(screen_name[3:])-1]
          else:
            return _('STATUS_NOT_FOUND') % screen_name
      try:
        self._api.report_spam(screen_name)
      except twitter.TwitterError, e:
        if 'Not found' in e.message:
          return _('USER_NOT_FOUND') % screen_name
        else:
          logging.warn('report_spam:\n', e.message)
          return ''
      return _('SUCCESSFULLY_SPAM') % screen_name
    raise NotImplementedError

  def func_unblock(self, args):
    if len(args) == 1:
      screen_name = args[0]
      if not _check_screen_name(screen_name):
        try:
          id = self._utils.restore_short_id(screen_name[0:3])
        except ValueError:
          return _('INVALID_USERNAME')
        else:
          status = self._api.get_status(id)
          if status and len(screen_name) == 3:
            screen_name = status['user']['screen_name']
          elif screen_name[3:].isdigit():
            names = re.findall('@(%s)' % _screen_name_regex, status['text'])
            if int(screen_name[3:])<=len(names):
              screen_name = names[int(screen_name[3:])-1]
          else:
            return _('STATUS_NOT_FOUND') % screen_name
      try:
        self._api.destroy_block(screen_name)
      except twitter.TwitterError, e:
        if 'Not found' in e.message:
          return _('USER_NOT_FOUND') % screen_name
        else:
          logging.warn('destroy_block:\n', e.message)
          return ''
      return _('SUCCESSFULLY_UNBLOCK') % screen_name
    raise NotImplementedError

  def func_del(self, args):
    length = len(args)
    id = None
    if 0 <= length <= 1:
      if not length:
        statuses = self._api.get_user_timeline(screen_name=self._google_user.enabled_user, count=1)
        if statuses:
          short_id = id = statuses[0]['id']
        else:
          return _('STATUS_NOT_FOUND') % ''
      else:
        short_id = args[0]
        try:
          id = self._utils.restore_short_id(short_id)
        except ValueError:
          pass
      if id:
        try:
          response = self._api.destroy_status(id)
        except twitter.TwitterError, e:
          if 'No status found' in e.message:
            return _('STATUS_NOT_FOUND') % short_id
          elif "You may not delete another user's status" in e.message:
            return _('DELETE_ANOTHER_USER_STATUS')
          else:
            logging.warn('destroy_status:\n', e.message)
            return ''
        if response is None:
          return
        else:
          return _('STATUS_DELETED') % (short_id, response['text'])
    raise NotImplementedError

  def func_on(self, args):
    if len(args):
      for a in args:
        if a == 'home':
          self._google_user.display_timeline |= MODE_HOME
        elif a == 'mention':
          self._google_user.display_timeline |= MODE_MENTION
        elif a == 'dm':
          self._google_user.display_timeline |= MODE_DM
        elif a == 'list':
          self._google_user.display_timeline |= MODE_LIST
    modes = []
    if self._google_user.display_timeline & MODE_LIST:
      modes.append('list')
    if self._google_user.display_timeline & MODE_HOME:
      modes.append('home')
    if self._google_user.display_timeline & MODE_MENTION:
      modes.append('mention')
    if self._google_user.display_timeline & MODE_DM:
      modes.append('dm')
    return _('ON_MODE') % ', '.join(modes)

  def func_off(self, args):
    if len(args):
      for a in args:
        if a == 'home':
          self._google_user.display_timeline &= ~MODE_HOME
        elif a == 'mention':
          self._google_user.display_timeline &= ~MODE_MENTION
        elif a == 'dm':
          self._google_user.display_timeline &= ~MODE_DM
        elif a == 'list':
          self._google_user.display_timeline &= ~MODE_LIST
    else:
      self._google_user.display_timeline = MODE_NONE
    return self.func_on([])

  def func_live(self, args):
    length = len(args)
    if not length:
      if self._google_user.list_user and self._google_user.list_id and self._google_user.list_name:
        return _('LIVE_MODE') % (self._google_user.list_user + '/' + self._google_user.list_name)
      return _('USE_LIVE')
    elif 1 <= length <= 2:
      if length == 1:
        path = args[0].split('/')
        if len(path) == 1:
          user = self._google_user.enabled_user
          list_id = path[0]
        elif len(path) == 2:
          user = path[0]
          list_id = path[1]
        else:
          raise NotImplementedError
      else:
        user = args[0]
        list_id = args[1]
      if not _check_screen_name(user):
        return _('INVALID_USERNAME')
      try:
        response = self._api.get_list(user, list_id)
      except twitter.TwitterError, e:
        if 'Not found' in e.message:
          return _('LIST_NOT_FOUND') % (list_id if user == self._google_user.enabled_user else user + '/' + list_id)
        else:
          logging.warn('get_list:\n', e.message)
          return ''
      if response is None:
        return None
      self._google_user.list_user = response['user']['screen_name']
      self._google_user.list_id = response['id']
      self._google_user.list_name = response['slug']
      return _('LIVE_MODE') % (self._google_user.list_user + '/' + self._google_user.list_name)
    raise NotImplementedError

  def func_fav(self, args):
    length = len(args)
    if not length or (length == 1 and (args[0][0].lower() == 'p' and args[0][1:].isdigit())):
      page = args[0][1:] if length else 1
      statuses = self._api.get_favorites(page=int(page))
      return _('FAVOURITES') + _('PAGE') % str(page) + '\n\n' + self._utils.parse_statuses(statuses)
    elif length == 1:
      short_id = args[0]
      try:
        id = self._utils.restore_short_id(short_id)
      except ValueError:
        pass
      else:
        try:
          self._api.create_favorite(id)
        except twitter.TwitterError, e:
          if 'No status found' in e.message:
            return _('STATUS_NOT_FOUND') % short_id
          else:
            logging.warn('create_favorite:\n', e.message)
            return ''
        return _('FAVOURITED') % short_id
    raise NotImplementedError

  def func_unfav(self, args):
    if len(args) == 1:
      short_id = args[0]
      try:
        id = self._utils.restore_short_id(short_id)
      except ValueError:
        pass
      else:
        try:
          self._api.destroy_favorite(id)
        except twitter.TwitterError, e:
          if 'No status found' in e.message:
            return _('STATUS_NOT_FOUND') % short_id
          else:
            logging.warn('destroy_favorite:\n', e.message)
            return ''
        return _('UNFAVOURITED') % short_id
    raise NotImplementedError

  def func_home(self, args):
    length = len(args)
    if not length:
      page = 1
    elif length == 1 and args[0][0].lower() == 'p' and args[0][1:].isdigit():
      page = args[0][1:]
    else:
      raise NotImplementedError
    try:
      statuses = self._api.get_home_timeline(page=int(page))
    except twitter.TwitterError, e:
      logging.warn('get_home_timeline:\n', e.message)
      return ''
    if statuses is None:
      return None
    return _('TIMELINE') + _('PAGE') % str(page) + '\n\n' + self._utils.parse_statuses(statuses)

  def func_timeline(self, args):
    length = len(args)
    if not length or (length == 1 and (args[0][0].lower() == 'p' and args[0][1:].isdigit())):
      screen_name = self._google_user.enabled_user
      page = args[0][1:] if length else 1
    elif length == 1 or (length == 2 and (args[1][0].lower() == 'p' and args[1][1:].isdigit())):
      screen_name = args[0]
      if not _check_screen_name(screen_name):
        try:
          id = self._utils.restore_short_id(screen_name[0:3])
        except ValueError:
          return _('INVALID_USERNAME')
        else:
          status = self._api.get_status(id)
          if status and len(screen_name) == 3:
            screen_name = status['user']['screen_name']
          elif screen_name[3:].isdigit():
            names = re.findall('@(%s)' % _screen_name_regex, status['text'])
            if int(screen_name[3:])<=len(names):
              screen_name = names[int(screen_name[3:])-1]
            else:
              return _('STATUS_NOT_FOUND') % screen_name
      page = args[1][1:] if length == 2 else 1
    else:
      raise NotImplementedError
    try:
      statuses = self._api.get_user_timeline(screen_name=screen_name, page=int(page))
    except twitter.TwitterError, e:
      if 'Not found' in e.message:
        return _('USER_NOT_FOUND') % screen_name
      elif 'Not authorized' in e.message:
        return _('PROTECTED_USER')
      else:
        logging.warn('get_user_timeline:\n', e.message)
        return ''
    if statuses is None:
      return ''
    return _('USER_TIMELINE') % screen_name + _('PAGE') % str(page) + '\n\n' + self._utils.parse_statuses(statuses)

  def func_list(self, args):
    length = len(args)
    if length == 0 or (length == 1 and (args[0][0]).lower() == 'p' and args[0][1:].isdigit()):
      if self._google_user.list_user and self._google_user.list_id and self._google_user.list_name:
        user = self._google_user.list_user
        list_id =  self._google_user.list_name
        if length ==1:
          page = int(args[0][1:])
        else:
          page = 1
      else:
        raise NotImplementedError
    elif length == 1 or (length == 2 and (args[1][0].lower() == 'p' and args[1][1:].isdigit())):
      path = args[0].split('/')
      if len(path) == 1:
        user = self._google_user.enabled_user
        list_id = path[0]
      elif len(path) == 2:
        user = path[0]
        list_id = path[1]
      else:
        raise NotImplementedError
      page = args[1][1:] if length == 2 else 1
    elif length == 2 or (length == 3 and (args[2][0].lower() == 'p' and args[2][1:].isdigit())):
      user = args[0]
      list_id = args[1]
      page = args[2][1:] if length == 3 else 1
    else:
      raise NotImplementedError
    if not _check_screen_name(user):
      return _('INVALID_USERNAME')
    if type(list_id) == unicode:
      list_id = list_id.encode('UTF8')
    try:
      statuses = self._api.get_list_statuses(user=user, id=list_id, page=int(page))
    except twitter.TwitterError, e:
      if 'Not found' in e.message:
        return _('LIST_NOT_FOUND') % args[0]
      else:
        logging.warn('get_list_statuses:\n', e.message)
        return ''
    if statuses is None:
      return ''
    return _('LIST') % (user + '/' + str(list_id)) + _('PAGE') % str(page) + '\n\n' + self._utils.parse_statuses(
      statuses)

  def func_ra(self, args):
    if len(args) > 1:
      short_id = args[0]
      try:
        id = self._utils.restore_short_id(short_id)
      except ValueError:
        pass
      else:
        try:
          status = self._api.get_status(id)
        except twitter.TwitterError, e:
          if 'No status found' in e.message:
            return _('STATUS_NOT_FOUND') % short_id
          else:
            logging.warn('get_status:\n', e.message)
            return ''
        if status is None:
          return ''
        mention_users = [status['user']['screen_name']]
        for name in re.findall('@(%s)' % _screen_name_regex, status['text']):
          if name != self._google_user.enabled_user and name not in mention_users:
            mention_users.append(name)
        message = u'%s %s' % (' '.join(['@' + x for x in mention_users]), ' '.join(args[1:]))
        if len(message) > twitter.CHARACTER_LIMIT:
          return _('WORDS_COUNT_EXCEED') % (len(message), twitter.CHARACTER_LIMIT)
        if type(message) == unicode:
          message = message.encode('UTF8')
        try:
          self._api.post_update(message, id)
        except twitter.TwitterError, e:
          if 'Status is a duplicate' in e.message:
            return _('STATUS_DUPLICATE')
          else:
            logging.warn('post_update:\n', e.message)
            return ''
        return _('SUCCESSFULLY_REPLY_TO') % ', '.join(mention_users)
    raise NotImplementedError

  def func_re(self, args):
    if len(args) == 1:
      short_id = args[0]
      try:
        id = self._utils.restore_short_id(short_id)
      except ValueError:
        pass
      else:
        try:
          self._api.create_retweet(id)
        except twitter.TwitterError, e:
          if 'No status found' in e.message:
            return _('STATUS_NOT_FOUND') % short_id
          else:
            logging.warn('create_retweet:\n', e.message)
            return ''
        return _('SUCCESSFULLY_RETWEET') % short_id
    raise NotImplementedError

  def func_rt(self, args):
    length = len(args)
    if length >= 1:
      short_id = args[0]
      try:
        id = self._utils.restore_short_id(short_id)
      except ValueError:
        pass
      else:
        try:
          status = self._api.get_status(id)
        except twitter.TwitterError, e:
          if 'No status found' in e.message:
            return _('STATUS_NOT_FOUND') % short_id
          else:
            logging.error('get_status:\n', e.message)
            return ''
        if status is None:
          return ''
        if length > 1:
          user_msg = ' '.join(args[1:])
          if ord(user_msg[-1]) < 128:
            user_msg += ' '
        else:
          user_msg = ''
        message = u'%sRT @%s:%s' % (user_msg, status['user']['screen_name'], status['text'])
        if len(message) > twitter.CHARACTER_LIMIT:
          message = message[:138] + '..'
        if type(message) == unicode:
          message = message.encode('UTF8')
        try:
          json = self._api.post_update(message, id)
        except twitter.TwitterError, e:
          if 'Status is a duplicate' in e.message:
            return _('STATUS_DUPLICATE')
          else:
            logging.warn('post_update:\n', e.message)
            return ''
        else:
          return _('SUCCESSFULLY_RT') % (short_id, Utils.parse_text(json['text']))
    raise NotImplementedError

  def func_user(self, args):
    length = len(args)
    if length > 1:
      raise NotImplementedError
    else:
      if not length:
        user = self._google_user.enabled_user
      else:
        user = args[0]
        if not _check_screen_name(user):
          try:
            id = self._utils.restore_short_id(user[0:3])
          except ValueError:
            return _('INVALID_USERNAME')
          else:
            status = self._api.get_status(id)
            if status and len(user) == 3:
              user = status['user']['screen_name']
            elif user[3:].isdigit():
              names = re.findall('@(%s)' % _screen_name_regex, status['text'])
              if int(user[3:])<=len(names):
                user = names[int(user[3:])-1]
            else:
              return _('STATUS_NOT_FOUND') % user
      try:
        result = self._api.get_user(user)
      except twitter.TwitterError, e:
        if 'Not found' in e.message:
          return _('USER_NOT_FOUND') % args[0]
        else:
          logging.warn('get_user:\n', e.message)
          return ''
      if result is None:
        return ''
      result['profile_image_url'] = result['profile_image_url'].replace('_normal.', '.')
      for x in result:
        if result[x] is None:
          result[x] = ''
      if 'status' in result and result['status']:
        result['status']['user'] = result
        result['status'] = self._utils.parse_status(result['status'])
      else:
        result['status'] = ''
      if result['following']:
        result['following'] = _('YOU_FOLLOWING') % result['screen_name']
      elif result['follow_request_sent']:
        result['following'] = _('YOU_HAVE_REQUESTED') % result['screen_name']
      else:
        result['following'] = _('YOU_DONT_FOLLOW') % result['screen_name']
      return Template(_('USER_PROFILE')).safe_substitute(result)



  def func_search(self,args):
    if args[-1][0] == 'p' and args[-1][1:].isdigit():
      page = int(args[-1][1:])
      text = ' '.join(args[0:-1])
    else:
      page = 1
      text = ' '.join(args)
    statuses = self._api.search_status(text,page)
    return  'SEARCH RESULT'+_('PAGE') % str(page) + '\n\n'+self._utils.parse_statuses(statuses['results'])



  def func_timezone(self, args):
    length = len(args)
    if not length:
      return _('CURRENT_TIMEZONE') % self._google_user.timezone
    elif length == 1:
      try:
        pytz.timezone(args[0])
      except pytz.UnknownTimeZoneError:
        return _('INVALID_TIMEZONE')
      self._google_user.timezone = args[0]
      return _('SET_TIMEZONE_SUCCESSFULLY')
    raise NotImplementedError

  def func_locale(self, args):
    length = len(args)
    if not length:
      return _('CURRENT_LOCALE') % LOCALES[self._google_user.locale]
    elif length == 1:
      if args[0] not in LOCALES:
        return _('INVALID_LOCALE')
      global _locale
      _locale = args[0]
      self._google_user.locale = args[0]
      return _('SET_LOCALE_SUCCESSFULLY')
    raise NotImplementedError

  def func_retweet(self, args):
    length = len(args)
    if length <= 1:
      if length == 1:
        value = args[0].lower()
        if value in ('true', '1', 'yes'):
          value = True
        elif value in ('false', '0', 'no'):
          value = False
        else:
          raise NotImplementedError
        self._google_user.official_retweet = value
      return _('RETWEET_MODE') if self._google_user.official_retweet else _('RT_MODE')
    raise NotImplementedError

  def func_bold(self, args):
    length = len(args)
    if length <= 1:
      if length == 1:
        value = args[0].lower()
        if value in ('true', '1', 'yes'):
          value = True
        elif value in ('false', '0', 'no'):
          value = False
        else:
          raise NotImplementedError
        self._google_user.bold_username = value
      return _('BOLD_MODE_ON') if self._google_user.bold_username else _('BOLD_MODE_OFF')
    raise NotImplementedError

  def func_reverse(self, args):
    length = len(args)
    if length <= 1:
      if length == 1:
        value = args[0].lower()
        if value in ('true', '1', 'yes'):
          value = True
        elif value in ('false', '0', 'no'):
          value = False
        else:
          raise NotImplementedError
        self._google_user.reverse = value
      return _('REVERSE_MODE_ON') if self._google_user.reverse else _('REVERSE_MODE_OFF')
    raise NotImplementedError

  def func_msgtpl(self, args):
    if len(args):
      tpl = ' '.join(args)
      while tpl[-2::] == r'\n':
        tpl = tpl[:len(tpl) - 2] + '\n'
      self._google_user.msg_template = tpl
    return _('MSG_TEMPLATE') % self._google_user.msg_template

  def func_datefmt(self, args):
    if len(args):
      self._google_user.date_format = ' '.join(args)
    return _('DATE_TEMPLATE') % self._google_user.date_format

  def func_prefix(self, args):
    length = len(args)
    if length <= 1:
      if length:
        self._google_user.command_prefix = args[0]
      return _('COMMAND_PREFIX') % self._google_user.command_prefix
    raise NotImplementedError

  def func_prefix_space(self, args):
    if not args:
      return self.func_prefix([' '])
    else:
      raise NotImplementedError

  def func_switch(self, args):
    length = len(args)
    if length > 1:
      raise NotImplementedError
    else:
      twitter_users = TwitterUser.get_by_jid(self._google_user.jid)
      twitter_users_name = [u.twitter_name for u in twitter_users if u.twitter_name is not None]
      if not length:
        return _('NOW_USING') % self._google_user.enabled_user + '\n'\
        + _('ALL_TWITTER_USERS_NAME') % '\n'.join(twitter_users_name)
      else:
        if not _check_screen_name(args[0]):
          if args[0][0] == '.' and args[0][1:].isdigit():
            if int(args[0][1:])<=len(twitter_users_name):
              self._google_user.enabled_user = twitter_users_name[int(args[0][1:])-1]
              return _('ENABLED_TWITTER_USER_CHANGED') % self._google_user.enabled_user
            else:
              return _('INVALID_USERNAME')
          else:
            return _('INVALID_USERNAME')
        twitter_users_name_ci = [x.lower() for x in twitter_users_name]
        twitter_name_ci = args[0].lower()
        if twitter_name_ci in twitter_users_name_ci:
          i = twitter_users_name_ci.index(twitter_name_ci)
          self._google_user.enabled_user = twitter_users_name[i]
          return _('ENABLED_TWITTER_USER_CHANGED') % self._google_user.enabled_user
    return _('NOT_ASSOCIATED_TWITTER_USER')

  def func_remove(self, args):
    length = len(args)
    msg = ''
    if length <= 1:
      if not length:
        user = self._google_user.enabled_user
      else:
        user = args[0]
        if not _check_screen_name(user):
          return _('INVALID_USERNAME')
      if user != '':
        twitter_user = TwitterUser.get_by_twitter_name(user, self._google_user.jid)
        if twitter_user is not None:
          twitter_user.delete()
          memcache.delete(self._google_user.jid + ':' + user, namespace='twitter_name')
          if self._google_user.enabled_user == user:
            self._google_user.enabled_user = ''
          msg += _('TWITTER_USER_DELETED') % user
      msg += _('SPECIFY_ANOTHER_USER')
      return msg
    raise NotImplementedError

  def func_oauth(self, args):
    length = len(args)
    if not length or length == 2:
      consumer = oauth.Consumer(config.OAUTH_CONSUMER_KEY, config.OAUTH_CONSUMER_SECRET)
      client = oauth.Client(consumer)
      resp = client.request(twitter.REQUEST_TOKEN_URL)
      if not resp:
        return _('NETWORK_ERROR')
      self._request_token = dict(cgi.parse_qsl(resp))
      oauth_token = self._request_token['oauth_token']
      redirect_url = "%s?oauth_token=%s" % (twitter.AUTHORIZATION_URL, oauth_token)
      if not length:
        TwitterUser.add(self._google_user.jid, oauth_token)
        return _('OAUTH_URL') % redirect_url
      import oauth_proxy
      from google.appengine.api import urlfetch_errors
      try:
        pin = oauth_proxy.login_oauth(redirect_url, args[0], args[1])
      except urlfetch_errors.Error:
        return _('NETWORK_ERROR')
      except twitter.TwitterAuthenticationError:
        return _('WRONG_USER_OR_PASSWORD')
      else:
        return self.func_bind([pin], oauth_token)
    else:
      raise NotImplementedError

  def func_bind(self, args, oauth_token=None):
    if len(args) == 1 and args[0].isdigit():
      twitter_user = None
      if oauth_token is None:
        twitter_user = TwitterUser.get_by_twitter_name(None, self._google_user.jid)
        if twitter_user is None:
          return _('INVALID_PIN_CODE') % ''
        oauth_token = twitter_user.access_token_key
      token = oauth.Token(oauth_token)
      if type(args[0]) != unicode:
        args[0] = args[0].encode('UTF8')
      token.set_verifier(args[0])
      consumer = oauth.Consumer(config.OAUTH_CONSUMER_KEY, config.OAUTH_CONSUMER_SECRET)
      client = oauth.Client(consumer, token)
      resp = client.request(twitter.ACCESS_TOKEN_URL, "POST")
      if not resp:
        return _('NETWORK_ERROR')
      access_token = dict(cgi.parse_qsl(resp))
      if 'oauth_token' not in access_token:
        return _('INVALID_PIN_CODE') % args[0]
      if twitter_user is not None:
        twitter_user.delete()
      TwitterUser.add(self._google_user.jid, access_token['oauth_token'], access_token['oauth_token_secret'],
                      access_token['screen_name'])
      if self._google_user.enabled_user == '':
        self._google_user.enabled_user = access_token['screen_name']
      if IdList.get_by_jid(self._google_user.jid, self._google_user.shard) is None:
        IdList.add(self._google_user.jid, self._google_user.shard)
      return _('SUCCESSFULLY_BIND') % access_token['screen_name']
    else:
      raise NotImplementedError

  def func_help(self, args):
    length = len(args)
    if not length:
      return _('ALL_COMMANDS')
    elif length == 1:
      command = args[0].lower()
      if command in SHORT_COMMANDS:
        command = SHORT_COMMANDS[command]
      if command == 'help':
        return _('ALL_COMMANDS')
      if command == 'locale':
        return _('HELP_LOCALE') % '\n'.join(k + ':' + LOCALES[k] for k in LOCALES)
      func_name = 'func_' + command
      if func_name in dir(self):
        return _('HELP_' + command.upper())
      else:
        return ''


if __name__ == "__main__":
  application = webapp.WSGIApplication([('/_ah/xmpp/message/chat/', XMPP_handler)])
  run_wsgi_app(application)
